
var SGAPI = {};

(function(){

    SGAPI.callback = {};

    var callbackCounter = 0;
    var beginRequestListener = function () {};
    var endRequestListener = function () {};
    var beginNetworkListener = function () {};
    var endNetworkListener = function () {};

    var outstandingRequests = 0;

    SGAPI.fetchResultsRaw = function (urls, args, callback) {
        if (urls.length) {

            // Allocate a callback slot.
            var callbackIndex = callbackCounter++;
            var callbackLocalName = "c"+callbackIndex;
            var callbackFullName = "SGAPI.callback."+callbackLocalName;
            args.callback = callbackFullName;

            args.q = urls.join(",");

            var queryStringBits = [];
            for (var key in args) {
                var value = args[key];

                if (value === true) value = "1";
                else if (value === false) value = "0";

                queryStringBits.push([
                                      encodeURIComponent(key),
                                      encodeURIComponent(value)
                                      ].join('='));
            }

            var queryString = queryStringBits.join("&");
            var url = [
                       "http://socialgraph.apis.google.com/lookup",
                       queryString
            ].join("?");

            var scriptNode = document.createElement("script");
            scriptNode.type = "text/javascript";
            scriptNode.src = url;

            var realCallback = function (data) {
                // Call the caller's callback
                callback(data);

                // Clean up our temporary junk
                if (scriptNode.parentNode) {
                    scriptNode.parentNode.removeChild(scriptNode);
                }
                SGAPI.callback[callbackLocalName] = undefined;
                outstandingRequests--;

                if (endRequestListener) {
                    endRequestListener(urls);
                }

                if (outstandingRequests == 0) {
                    // We're now idle, so let's take an opportunity to
                    // reset everything.
                    SGAPI.callback = [];
                    callbackCounter = 0;

                    if (endNetworkListener) {
                        endNetworkListener();
                    }
                }
            };

            if (outstandingRequests == 0) {
                if (beginNetworkListener) {
                    beginNetworkListener();
                }
            }
            beginRequestListener(urls);
            outstandingRequests++;


            SGAPI.callback[callbackLocalName] = realCallback;
            document.body.appendChild(scriptNode);
        }
        else {
            // If we've actually been given an empty list for some reason,
            // let's just return immediately.
            realCallback({
                canonical_mapping: {},
                nodes: {}
            });
        }

    };

    SGAPI.fetchResults = function (urls, args, callback) {
            var nextUrlIdx = 0;
            var urlCount = urls.length;

            var result = {
                canonical_mapping: {},
                nodes: {}
            };

            var fetchSomeResults;
            fetchSomeResults = function () {
                var someUrls = [];

                var stop = nextUrlIdx + 15;
                if (stop > urlCount) stop = urlCount;

                var stringLength = 0;

                while (1) {
                    var nextUrl = urls[nextUrlIdx];
                    someUrls.push(nextUrl);
                    stringLength += nextUrl.length + 1;
                    nextUrlIdx++;
                    if (stringLength >= 600) break;
                    if (nextUrlIdx >= stop) break;
                }

                SGAPI.fetchResultsRaw(someUrls, args, function (data) {
                    for (url in data.canonical_mapping) {
                        result.canonical_mapping[url] = data.canonical_mapping[url];
                    }
                    for (url in data.nodes) {
                        result.nodes[url] = data.nodes[url];
                    }
                    if (nextUrlIdx == urlCount) {
                        // We're finished.
                        callback(result);
                    }
                    else {
                        // Need to fetch some more results
                        fetchSomeResults();
                    }
                });
            };

            fetchSomeResults();
    };

    SGAPI.setBeginRequestListener = function (callback) {
        beginRequestListener = callback;
    };
    SGAPI.setEndRequestListener = function (callback) {
        endRequestListener = callback;
    };
    SGAPI.setBeginNetworkListener = function (callback) {
        beginNetworkListener = callback;
    };
    SGAPI.setEndNetworkListener = function (callback) {
        endNetworkListener = callback;
    };

})();

